
#include "MaterialManager.hpp"
#include "Adapter.hpp"
#include "Core.hpp"
#include "Exception.hpp"
#include "Shader.hpp"

namespace VoodooShader
{
	MaterialManager::MaterialManager(Core * parent)
		: mParent(parent), mDefault(NULL)
	{ };

	void MaterialManager::Add(Texture * texture, Shader * shader, bool global)
	{
		// Search the map for the texture
		MaterialMap::iterator material = this->mMaterials.find(texture);

		if ( material != this->mMaterials.end() )
		{
			// Rebind it if found
			material->second = shader;
		} else {
			// Insert this material into the map
			this->mMaterials[texture] = shader;
		}

		// If the global parameter is set, set this as the global shader.
		if ( global )
		{
			this->mDefault = shader;
		}
	}

	void MaterialManager::Remove(Texture * texture)
	{
		MaterialMap::iterator material = this->mMaterials.find(texture);

		if ( material != this->mMaterials.end() )
		{
			this->mMaterials.erase(material);	
		} else {
			Throw("Voodoo Core: Texture not present in material map.", this->mParent);
		}
	}

	void MaterialManager::Bind(Texture * texture)
	{
		Adapter * adapter = this->mParent->GetAdapter();

		if ( !adapter )
		{
			Throw("Voodoo Core: Attempted to bind material with no adapter set.", this->mParent);
		}

		MaterialMap::iterator material = this->mMaterials.find(texture);

		if ( material != this->mMaterials.end() )
		{
			Shader * shader = material->second;
			adapter->Bind(shader);
			this->mBound = shader;		
		} else {
			if ( this->mDefault )
			{
				adapter->Bind(this->mDefault);
				this->mBound = this->mDefault;
			} else {
				Throw("Voodoo Core: Could not find material to bind.", this->mParent);
			}
		}
	}

	void MaterialManager::Unbind()
	{
		if ( this->mBound )
		{
			Adapter * adapter = this->mParent->GetAdapter();

			if ( !adapter )
			{
				Throw("Voodoo Core: Attempted to unbind material with no adapter set.", this->mParent);
			}

			adapter->Unbind();
			this->mBound = NULL;
		}
	}


	Shader * MaterialManager::Find(Texture * texture)
	{
		MaterialMap::iterator material = this->mMaterials.find(texture);

		if ( material != this->mMaterials.end() )
		{
			return material->second;
		} else {
			return NULL;
		}
	}
}